﻿using System;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Threading;
using TSharpPool = Amib.Threading.SmartThreadPool;
using Moq;
using System.Web;
using System.Security.Principal;
using System.Collections.Generic;
using System.Security.Cryptography;

using System.IO;

using System.Runtime.CompilerServices;

using System.Collections;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TSharp.Core.Osgi;

namespace TSharp.Core.Threading
{

    /// <summary>
    /// 测试辅助
    /// <para>2011/1/12</para>
    /// 	<para>TANGJINGBO</para>
    /// 	<author>tangjingbo</author>
    /// </summary>
    public static class TestHelper
    {
        /// <summary>
        /// Mies the class initialize.
        /// </summary>
        /// <param name="context">The context.</param>
        public static void MyClassInitialize(TestContext context)
        {
            string basePath = Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
            var _engine = new OsgiEngine(basePath, basePath, "");

        }
        /// <summary>
        /// Fakes the HTTP request.
        /// </summary>
        /// <returns></returns>
        public static Mock<HttpRequestBase> FakeHttpRequest()
        {
            var request = new Mock<HttpRequestBase>();
            request.Setup(req => req.ApplicationPath).Returns("~/");
            request.Setup(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/");
            request.Setup(req => req.PathInfo).Returns(string.Empty);

            return request;
        }
        /// <summary>
        /// Fakes the HTTP session.
        /// </summary>
        /// <returns></returns>
        public static Mock<HttpSessionStateBase> FakeHttpSession()
        {
            var session = new Mock<HttpSessionStateBase>();
            session.Setup(x => x.IsNewSession).Returns(false);
            session.Setup(x => x.SessionID).Returns(Guid.NewGuid().ToString());
            session.Setup(x => x.SyncRoot).Returns(new object());
            return session;
        }
        /// <summary>
        /// Fakes the HTTP response.
        /// </summary>
        /// <returns></returns>
        public static Mock<HttpResponseBase> FakeHttpResponse()
        {
            var response = new Mock<HttpResponseBase>();
            response.Setup(res => res.ApplyAppPathModifier(It.IsAny<string>()))
             .Returns((string virtualPath) => virtualPath);
            return response;
        }
        /// <summary>
        /// Fakes the HTTP server utility.
        /// </summary>
        /// <returns></returns>
        public static Mock<HttpServerUtilityBase> FakeHttpServerUtility()
        {
            var server = new Mock<HttpServerUtilityBase>();

            return server;
        }
        /// <summary>
        /// Fakes the identity.
        /// </summary>
        /// <returns></returns>
        public static Mock<IIdentity> FakeIdentity()
        {
            var identity = new Mock<IIdentity>();

            identity.SetupGet(ident => ident.IsAuthenticated).Returns(true);


            return identity;
        }
        /// <summary>
        /// Fakes the I principal.
        /// </summary>
        /// <returns></returns>
        public static Mock<IPrincipal> FakeIPrincipal()
        {
            var user = new Mock<IPrincipal>();
            user.Setup(usr => usr.Identity).Returns(FakeIdentity().Object);
            return user;
        }
        /// <summary>
        /// Fakes the state of the HTTP application.
        /// </summary>
        /// <returns></returns>
        public static Mock<HttpApplicationStateBase> FakeHttpApplicationState()
        {
            var application = new Mock<HttpApplicationStateBase>();

            return application;
        }

        /// <summary>
        /// Fakes the HTTP context.
        /// </summary>
        /// <returns></returns>
        public static Mock<HttpContextBase> FakeHttpContext()
        {
            var context = new Mock<HttpContextBase>();
            context.Setup(ctx => ctx.Request).Returns(FakeHttpRequest().Object);
            context.Setup(ctx => ctx.Response).Returns(FakeHttpResponse().Object);
            context.Setup(ctx => ctx.Session).Returns(FakeHttpSession().Object);
            context.Setup(ctx => ctx.Server).Returns(FakeHttpServerUtility().Object);
            context.Setup(ctx => ctx.User).Returns(FakeIPrincipal().Object);
            context.Setup(x => x.Application).Returns(FakeHttpApplicationState().Object);
            context.Setup(ctx => ctx.Items).Returns(new Hashtable());

            return context;
        }
        /// <summary>
        /// Multis the thread ladder logic test.
        /// </summary>
        /// <param name="action">The action.</param>
        public static void MultiThreadLadderLogicTest(Action action)
        {
            MultiThreadLadderLogicTest(action, 30);
        }
        /// <summary>
        /// Multis the thread ladder logic test.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <param name="queueCount">The queue count.</param>
        public static void MultiThreadLadderLogicTest(Action action, int queueCount)
        {
            MultiThreadLadderLogicTest(action, queueCount, string.Empty);
        }
        /// <summary>
        /// Multis the thread ladder logic test.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <param name="queueCount">The queue count.</param>
        /// <param name="info">The info.</param>
        public static void MultiThreadLadderLogicTest(Action action, int queueCount, string info)
        {
            Console.WriteLine(info + " 测试开始！");
            Console.WriteLine("#线程名称[执行次序]#次数  |运行时间");
            Console.WriteLine();
            Stopwatch sw = Stopwatch.StartNew();
            sw.Start();
            using (var sp = new TSharpPool())
            {
                sp.Name = "";
                var item = new WorkItem((Action)action.Clone(), 1);
                for (int i = 0, n = queueCount; i < n; i++)
                {
                    sp.QueueWorkItem(a => { a.Run(); }, item);
                }

                sp.Start();
                sp.WaitForIdle();
                sp.Shutdown(false, TimeSpan.FromMinutes(3));
            }
            sw.Stop();
            Console.WriteLine(string.Format("测试完毕！总计{0}秒", sw.Elapsed.TotalSeconds));
        }

        /// <summary>
        /// Ladders the logic test.
        /// </summary>
        /// <param name="action">The action.</param>
        public static void LadderLogicTest(Action action)
        {
            new WorkItem(action, 1).Run();
        }

        #region Nested type: WorkItem

        /// <summary>
        /// 
        /// <para>2011/2/25</para>
        /// 	<para>THINKPADT61</para>
        /// 	<para>tangjingbo</para>
        /// </summary>
        public class WorkItem
        {
            private readonly Action action;
            private readonly int baseTimes;

            /// <summary>
            /// Initializes a new instance of the <see cref="WorkItem"/> class.
            /// </summary>
            /// <param name="action">The action.</param>
            /// <param name="baseTimes">The base times.</param>
            public WorkItem(Action action, int baseTimes)
            {
                this.action = action;
                this.baseTimes = baseTimes;
            }

            /// <summary>
            /// Runs this instance.
            /// </summary>
            public void Run()
            {
                LadderLogicTest(action, baseTimes);
            }

            private void Record(StringBuilder outer, int runtimes, long Elapsed, string custom, int nth)
            {
                int space = 10 - runtimes.ToString().Length;
                if (space < 0)
                    space = 0;
                outer.AppendLine(string.Format("{4}[{5}]#{0}{1}|{2}{3}",
                                               runtimes,
                                               new string(' ', space),
                                               Elapsed,
                                               custom,
                                               Thread.CurrentThread.Name.Replace("STP  Thread ", ""),
                                               nth
                                     ));
            }

            private void LadderLogicTest(Action _action, int baseTimes)
            {
                try
                {
                    var sb = new StringBuilder();
                    Stopwatch sc = Stopwatch.StartNew();
                    sc.Start();
                    _action();
                    sc.Stop();
                    Record(sb, 1, sc.ElapsedMilliseconds, " 第一次总是耗费很多时间", 0);

                    long all = 0;
                    for (int iStep = 0, maxStep = 10; iStep <= maxStep; iStep++)
                    {
                        int n = baseTimes * Convert.ToInt32(Math.Pow(10, iStep));
                        sc.Reset();
                        sc.Start();
                        for (int i = 0; i < n; i++)
                            _action();
                        sc.Stop();
                        Record(sb, n, sc.ElapsedMilliseconds, "", iStep + 1);
                        all += sc.ElapsedMilliseconds;
                        if (sc.ElapsedMilliseconds > 5000)
                            break; //超过12秒就退出，不再测试
                    }
                    sb.AppendLine(string.Format("计:{0}秒", all / 1000));
                    Console.WriteLine(sb);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    throw new Exception(ex.Message, ex);
                }
            }
        }

        #endregion
        private readonly static RandomNumberGenerator randomGenerator = RandomNumberGenerator.Create();

        /// <summary>
        /// Gets the rondom string.
        /// </summary>
        /// <param name="length">The length.</param>
        /// <returns></returns>
        public static string GetRondomString(int length)
        {
            byte[] bytes = new byte[(length + 1) / 2];
            randomGenerator.GetBytes(bytes);
            StringBuilder sb = new StringBuilder();
            foreach (var b in bytes)
                sb.AppendFormat("{0:x2}", b);
            sb.Length = length;
            return sb.ToString();
        }
        private readonly static Random Generator = new Random(3);
        /// <summary>
        /// Gets the rondom string1.
        /// </summary>
        /// <param name="length">The length.</param>
        /// <returns></returns>
        public static string GetRondomString1(int length)
        {
            byte[] bytes = new byte[(length + 1) / 2];
            Generator.NextBytes(bytes);
            StringBuilder sb = new StringBuilder();
            foreach (var b in bytes)
                sb.AppendFormat("{0:x2}", b);
            sb.Length = length;
            return sb.ToString();
        }
    }
}
